package com.cn.gmall.activity.receiver;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cn.gmall.activity.mapper.SeckillGoodsMapper;
import com.cn.gmall.activity.service.SeckillGoodsService;
import com.cn.gmall.common.constant.RedisConst;
import com.cn.gmall.common.mqconst.MqConst;
import com.cn.gmall.common.util.DateUtil;
import com.cn.gmall.model.activity.SeckillGoods;
import com.cn.gmall.model.activity.UserRecode;
import com.mysql.cj.QueryReturnType;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class ActivityReceiver {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private SeckillGoodsService seckillGoodsService;

    /***
     * 每天一个固定时间 清除秒杀的商品缓存
     * @param message
     * @param channel
     */

    @RabbitListener(bindings = @QueueBinding(
            value =@Queue(value = MqConst.QUEUE_TASK_18,durable = "true",autoDelete = "false"),
            exchange =@Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_18}
    ))
    @SneakyThrows
    public void clearRedisData(Message message, Channel channel){
        System.out.println("收到清除缓存消息");
        try {
            //构建条件对象
            QueryWrapper<SeckillGoods> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("status","1");
            queryWrapper.le("end_time",new Date());
            //查询秒杀时间结束的商品
            List<SeckillGoods> seckillGoods = seckillGoodsMapper.selectList(queryWrapper);
            //判断
            if(!CollectionUtils.isEmpty(seckillGoods)){

                for (SeckillGoods seckillGood : seckillGoods) {
                    //清除商品列表数据
                    redisTemplate.opsForHash().delete(RedisConst.SECKILL_GOODS,seckillGood.getSkuId().toString());
                    //清除临时订单数据
                    redisTemplate.delete(RedisConst.SECKILL_ORDERS);
                    //清除秒杀订单数据
                    redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);
                    //清除库存
                    redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillGood.getSkuId());

                }

            }
        } catch (Exception e) {
            //收集问题，通知处理人
            e.printStackTrace();
        }

        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }





    /**
     * 用户秒杀下单 监听
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value =@Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false") ,
            exchange =@Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER) ,
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void  seckillUserDo(UserRecode userRecode,Message message , Channel channel){
        try {
            //判断
            if(userRecode!=null){

                System.out.println(userRecode);

                seckillGoodsService.seckillUser(userRecode.getSkuId(),userRecode.getUserId());
            }
        } catch (Exception e) {
            //通知管理人员
            e.printStackTrace();
        }


        //手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }









    /***
     * 商品预热
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}
    ))
    public void importToRedis(Message message, Channel channel) {

        System.out.println("收到加入秒杀商品缓存 消息" );// 测试
//        查询 mysql里面符合的数据 要在sql语句中使用 聚合函数用QueryWrapper

        QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "1"); //1 --> 能抢
        queryWrapper.gt("stock_count", 0); // 表示有库存
//        时间(秒杀开始的时间)
        queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
        List<SeckillGoods> seckillGoods = seckillGoodsMapper.selectList(queryWrapper);
//2. 将符合的商品 上传到redis(用hash存储)
        if (!CollectionUtils.isEmpty(seckillGoods)) {
//            遍历上传
            for (SeckillGoods seckillGood : seckillGoods) {
// ---------------- 查询是否存在该商品------------------

                BoundHashOperations<String,String,SeckillGoods> boundHashOperations = redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS);
                if(boundHashOperations.hasKey(seckillGood.getSkuId().toString())){
    //----------------如果存在跳出本次循环--------------
                    continue;
                }
//---------------计算商品秒杀时间的差值--------------
                Long timeSubtract = DateUtil.getTimeSubtract(seckillGood.getEndTime(), new Date());

//---------------存储到redis-----------------
                boundHashOperations.put(seckillGood.getSkuId().toString(),seckillGood);
 //-------------------设置数据的超时时间-------------
                boundHashOperations.expire(timeSubtract, TimeUnit.SECONDS);
//--------------遍历商品的库存数量-------------
                for (Integer i = 0; i < seckillGood.getStockCount(); i++) {
//----------------控制库存超卖-----秒杀锁库存----------
                    redisTemplate.opsForList().leftPush(RedisConst.SECKILL_STOCK_PREFIX+seckillGood.getSkuId(),seckillGood.getSkuId().toString());

                }


                //状态位 ---作用快速的响应商品是否还有库存 key:23  value :1 有库存  0 已售罄
                //需要进行状态位同步
                //redis--发布与订阅 (解决集群 不用创建多个队列的问题)
//                CacheHelper.put(seckillGood.getSkuId().toString(),"1");

                redisTemplate.convertAndSend("seckillPush",seckillGood.getSkuId()+":1");

            }
        }


        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}
